<html>
<head>
	<title>Wave Walls</title>
		<script src="utils.js" type="text/javascript"></script>
		<script src="rpc.js" type="text/javascript"></script>
		<script src="common.pbjson.js" type="text/javascript"></script>
		<script src="waveclient-rpc.pbjson.js" type="text/javascript"></script>
		<script src="webclient.pbjson.js" type="text/javascript"></script>
		<script src="jsot.js" type="text/javascript"></script>
	<style type="text/css">
body { font-family:aria,sans-serif; }
#login { position:absolute; top:0px; left:0px; }
#app { position:absolute; top:0px; left:0px;visibility:hidden;width:100% }
#titlebar { }
#appcontent { position:relative; width:100%; }
#wall { position:absolute; top:0px; left:0px; width:100% }
#messages { background-color:#E3E9F0; padding:6px 6px 10px 10px }
.messageframe { background-color:#FFFFFF; padding:0px; font-size:80%; margin-bottom:10px }
.frame1 { display:block; height:1px;border-left:5px solid #FFFFFF; border-right:5px solid #FFFFFF; border-color:#E3E9F0; }
.frame1b { background:#BCBCBC none repeat scroll 0 0; border-left:1px solid #BCBCBC; border-right:1px solid #BCBCBC; height:1px; display:block; font-size:0; line-height:0; overflow:hidden; position:relative; z-index:1; }
.frame2 { display:block; height:1px;border-left:3px solid #FFFFFF; border-right:3px solid #FFFFFF; border-color:#E3E9F0; }
.frame2b { border-left:2px solid #BCBCBC; border-right:2px solid #BCBCBC; height:1px; display:block; font-size:0; line-height:0; overflow:hidden; position:relative; z-index:1; }
.frame3 { display:block; height:2px;border-left:2px solid #FFFFFF; border-right:2px solid #FFFFFF; border-color:#E3E9F0; }
.frame3b { border-left:1px solid #BCBCBC; border-right:1px solid #BCBCBC; height:2px; display:block; font-size:0; line-height:0; overflow:hidden; position:relative; z-index:1; }
.messagemain { position:relative; background-color:#FFFFFF; border-color:#D7DDE3; border-left:1px solid #EFEFEF; border-right:1px solid #EFEFEF; }
.messageinnerframe { border-left:1px solid #BCBCBC; border-right:1px solid #BCBCBC; padding:6px 6px 10px 10px; margin:0px }
.messageactions { float:right; display:inline;  margin-right:-6px; margin-top:-10px; padding-left:6px; padding-right:6px; }
.messageimage { float:left; }
.userimage { width:45px;height:45px; }
.messagedate { float:right; margin-right:4px; margin-top:-10px; color:#777777 }
.messagebody { margin-left:55px }
.username { text-decoration:none; color:#114170; font-weight:bold }
.hline { background-color:#E2E2E2; font-size:0; height:1px; margin:13px 20px 3px 0; }
.like { padding:10px 0px 3px 0px; max-width:50em }
.liketext { color:#777777 }
.likeusername { text-decoration:none; color:#114170 }
.comment { padding:10px 0px 3px 0px; max-width:50em; margin-left:15px }
.commentspan { margin-left:-15px }
.commentdate { color:#777777 }
.messagebottom { border-left:1px solid #BCBCBC; border-right:1px solid #BCBCBC; padding:0px; margin:0px; background-color:#E3E9F0 }
.messagecontrolsbox { margin-left:65px }
.frame4 { display:block; height:2px;border-left:2px solid #FFFFFF; border-right:2px solid #FFFFFF; border-color:#E3E9F0; background-color:#E3E9F0 }
.frame4b { border-left:1px solid #BCBCBC; border-right:1px solid #BCBCBC; height:2px; display:block; font-size:0; line-height:0; overflow:hidden; position:relative; z-index:1; }
.frame5 { display:block; height:1px;border-left:3px solid #FFFFFF; border-right:3px solid #FFFFFF; border-color:#E3E9F0; background-color:#E3E9F0 }
.frame5b { border-left:2px solid #BCBCBC; border-right:2px solid #BCBCBC; height:1px; display:block; font-size:0; line-height:0; overflow:hidden; position:relative; z-index:1; }
.frame6 { display:block; height:1px;border-left:5px solid #FFFFFF; border-right:5px solid #FFFFFF; border-color:#E3E9F0; }
.frame6b { background:#BCBCBC none repeat scroll 0 0; border-left:1px solid #BCBCBC; border-right:1px solid #BCBCBC; height:1px; display:block; font-size:0; line-height:0; overflow:hidden; position:relative; z-index:1; }
#newsfeed { position:absolute; top:0px; left:0px; }
#friends { position:absolute; top:0px; left:0px; }
.commentbox { padding-top:6px; padding-bottom:2px }
.commentimage { float:left; margin-left:10px }
.commentnamebox { margin-bottom:2px; margin-left:65px }
.commentauthor { color:black; font-weight:bold; text-decoration:none }
.commenttextbox { background-color:#FFFFFF; padding:2px; margin:0px; width:53em;  margin-left:65px }
.commenttextarea { font-family:arial,sans-serif; font-size:inherit; background-color:#FFFFFF; outline-style:none; outline-width:0; border:none; width:53em }
.commentbuttonbox { margin:0; margin-top:2px; margin-left:63px }
.changetextarea { font-family:arial,sans-serif; font-size:inherit; background-color:#FFFFFF; outline:1px solid #E3E9F0; border:none; width:53em }
.editlink { margin-left:6px; margin-right:6px }

	</style>	
</head>
<body>
	<div id="login">
		<form>
			<p>User JID: <input type="text" id="jid" value="tux" />@wave1.vs.uni-due.de</p>
			<p><input type="button" value="Login" onclick="login()" /></p>
			<p id="logintext"></p>
		</form>
	</div>
	<div id="app" style="visibility:hidden">
		<div id="titlebar"><a href="javascript:showWall()" >Wall</a> <a href="javascript:showNewsfeed()" >Newsfeed</a> <a href="javascript:showFriends()" >Friends</a></div>
		<div id="appcontent">
			<div id="wall">
				<h1>Wall</h1>
				
				<div id="input" style="background-color:#999999; padding:10px; font-size:80%">
					<div style="float:left; margin-right:10px; margin-left:10px; margin-top:2px">
						<img src="https://mail.google.com/mail/images/blue_ghost.jpg" class="userimage" />
					</div>
					<div style="float:left; ">
						<div style="margin-bottom:2px"><a href="#" style="color:#E3E3E3" id="username"></a></div>
						<div style="background-color:#FFFFFF; padding:10px; margin:0px">
							<textarea id="inputtext" style="font-family:arial,sans-serif; font-size:inherit; background-color:#FFFFFF; outline-style:none; outline-width:0; width:52em; border:none"></textarea>
						</div>
						<div style="margin:0; margin-top:2px; margin-left:-2px">
							<input type="button" value="Publish" onclick="publish()" />
						</div>
					</div>
					<div style="clear:both"></div>
				</div>
				<div id="messages">
<!--				
					<div class="messageframe">
						<b class="frame1" >
							<b class="frame1b"></b>
						</b>
						<b class="frame2">
							<b class="frame2b"></b>
						</b>
						<b class="frame3">
							<b class="frame3b"></b>
						</b>
						<div class="messagemain">
							<div class="messageinnerframe">
								<div class="messageactions" ><a href="#">Actions</a></div>
								<span class="messageimage"><img src="foo.jpg" class="userimage" /></span>
								<span class="messagedate">9. March</span>
								<div class="messagebody">
									<div class="author"><a href="#" class="username">Joe Doe</a></div>
									<div class="content">
										<div><textarea class="changetextarea"></textarea></div>
										<div><input type="button" value="Publish" /> <input type="button" value="Delete" /> <input type="button" value="Cancel" /></div>
									</div>
									<div class="content">Here we can say what we always wanted to tell</div>
									<div class="hline"></div>
									<div class="like"><span class="liketext">One person liked this. - </span><a href="#" class="likeusername">Torben</a></div>
									<div class="comment"><span class="commentspan"><a href="#" class="username">Heinz Wurst</a> - This is some comment that is supposed to be longer than a single line to show what happens if it becomes too long and the text breaks around. <span class="commentdate">9. March</span></span></div>
								</div>
							</div>
							<div class="messagebottom">
								<div class="messagecontrolsbox"><a href="#">Comment<a> <a href="#">Like</a></div>
								<div class="commentbox">
								<span class="commentimage"><img src="https://mail.google.com/mail/images/blue_ghost.jpg" class="userimage" /></span>
								<div style="display:inline;">
									<div class="commentnamebox"><a href="#" class="commentauthor">Torben Weis</a></div>
									<div class="commenttextbox">
										<textarea class="commenttextarea"></textarea>
									</div>
								</div>
								<div class="commentbuttonbox">
									<input type="button" value="Publish" onclick="publish()" /> <input type="button" value="Cancel" onclick="" />
								</div>
								<div style="clear:both"></div>
								</div>
							</div>
						</div>
						<b class="frame4">
							<b class="frame4b"></b>
						</b>
						<b class="frame5">
							<b class="frame5b"></b>
						</b>
						<b class="frame6">
							<b class="frame6b"></b>
						</b>
					</div>
				-->
				</div>
			</div>
			<div id="newsfeed" style="visibility:hidden">
				<h1>Newsfeed</h1>
			</div>
			<div id="friends" style="visibility:hidden">
				<h1>Friends</h1>
			</div>
		</div>
	</div>
	<script type="text/javascript">
	
/**
 * Called when clicking on login
 */
function login()
{
	document.getElementById('logintext').innerHTML = "Logging in ... please wait";
	// Login at the wave server
	JSOT.Rpc.login( document.getElementById('jid').value + "@wave1.vs.uni-due.de", onLogin );
}

/**
 * Called when the server has logged us in
 */
function onLogin()
{
	document.getElementById( 'login' ).style.visibility = "hidden";
	document.getElementById( 'app' ).style.visibility = "visible";
	document.getElementById( 'username' ).innerHTML = JSOT.Rpc.jid;
	
	// Initialize the wave
	var wave = JSOT.Wave.getWave( "w+wall", "wave1.vs.uni-due.de" );
	var wavelet = wave.getWavelet( "conv+root", "wave1.vs.uni-due.de" );
	// Register event handlers to become notified when something changes
	var mainDoc = wavelet.getDoc("conversation");
	mainDoc.getEvent("newChild").addListener( conversationNewChild );
	mainDoc.getEvent("removeChild").addListener( conversationRemoveChild );
	mainDoc.createGUI();
	
	// Open the wave
	JSOT.Rpc.openWavelet( "wave://wave1.vs.uni-due.de/w+wall/conv+root" );
}

/**
 * GUI
 */
function showWall()
{
	document.getElementById( 'newsfeed' ).style.visibility = "hidden";
	document.getElementById( 'friends' ).style.visibility = "hidden";
	document.getElementById( 'wall' ).style.visibility = "visible";
}

/**
 * GUI
 */
function showNewsfeed()
{
	document.getElementById( 'wall' ).style.visibility = "hidden";
	document.getElementById( 'friends' ).style.visibility = "hidden";
	document.getElementById( 'newsfeed' ).style.visibility = "visible";
}

/**
 * GUI
 */
function showFriends()
{
	document.getElementById( 'newsfeed' ).style.visibility = "hidden";
	document.getElementById( 'wall' ).style.visibility = "hidden";
	document.getElementById( 'friends' ).style.visibility = "visible";
}

/**
 * GUI: Creates the DOM for a new message
 */
function newMessage(doc)
{
	var dom = document.createElement( "div" );
	dom.className = "messageframe";
	var html = '<b class="frame1" ><b class="frame1b"></b></b><b class="frame2"><b class="frame2b"></b></b><b class="frame3"><b class="frame3b"></b></b>' +
				'<div class="messagemain"><div class="messageinnerframe">' +
				'<div class="messageactions" ><a href="#">Actions</a></div>' + 
				'<span class="messageimage"><img src="https://mail.google.com/mail/images/blue_ghost.jpg" class="userimage" /></span>' +
				'<span class="messagedate"></span><div class="messagebody">' +
				'<div class="author"><a href="#" class="username"></a></div>' +
				'<div class="content"></div>' +
				'</div></div>' +
				'<div class="messagebottom"><div class="messagecontrolsbox"><a href="#" class="controlcomment">Comment<a> <a href="#" class="controllike">Like</a></div></div></div>' +
				'<b class="frame4"><b class="frame4b"></b></b><b class="frame5"><b class="frame5b"></b></b><b class="frame6"><b class="frame6b"></b></b>';
	dom.innerHTML = html;
	
	// Connect button with event handler
	var like = getElementByClass( dom, "controllike" );
	like.href = 'javascript:like("' + doc.docId + '")';

	// Connect button with event handler
	var comment = getElementByClass( dom, "controlcomment" );
	comment.href = 'javascript:createCommentBox("' + doc.docId + '")';

	return dom;
}

function updateLike( message, remove )
{
	var likes = message.doc.getElementsByType("like");

	// Nobody likes it anymore? Then remove the corresponding HTML
	var like = getElementByClass( message.dom, "like" );
	var hline = getElementByClass( message.dom, "hline" );
	if ( likes.length == 0 || ( remove && likes.length == 1 ) )
	{
		if ( like ) like.parentNode.removeChild(like);
		
		if ( hline && message.doc.getElementsByType("comment").length == 0 )
			hline.parentNode.removeChild(hline);
		return;
	}
	
	var dom = getElementByClass( message.dom, "content" );
	// Doew the hline exist already?
	if ( !hline )
	{
		hline = document.createElement("div");
		hline.className = "hline";
		dom.parentNode.insertBefore( hline, dom.nextSibling );
	}
	// Create the like div
	if ( !like )
	{
		like = document.createElement("div");
		like.className = "like";
		dom.parentNode.insertBefore( like, hline.nextSibling );
	}
	else
		like.innerHTML = "";
	// Create the liketext span
	var liketext = document.createElement("span");
	liketext.className = "liketext";
	liketext.appendChild( document.createTextNode("") );
	like.appendChild( liketext );
	// Construct the text to show
	var t = " this. - ";
	var count = likes.length;
	if ( remove )
		count--;
	if ( count == 1 )
		t = "One person likes" + t;
	else if ( count == 2 ) 
		t = "Two persons like" + t;
	else if ( count == 3 ) 
		t = "Three persons like" + t;
	else
		t = count.toString() + " persons like" + t;
	liketext.childNodes[0].data = t;
	var isliked = false;
	var count = 0;
	for( var i = 0; i < likes.length; ++i )
	{
		var a = document.createElement("a");
		a.className = "likeusername";
		a.href = "#";
		var t = "";
		if ( count > 0 )
			t += ", ";
		var author = likes[i].attributes["author"];
		if ( author == remove )
			continue;
		t += author;
		if ( author == JSOT.Rpc.jid )
			isliked = true;
		a.appendChild( document.createTextNode( t ) );
		like.insertBefore( a, null );
		count++;
	}
	
	var control = getElementByClass( message.dom, "controllike" );
	if ( isliked )	
		control.innerHTML = "Dislike";
	else
		control.innerHTML = "Like";
}

function contentTextChange( eventArgs )
{
	var dom = getElementByClass( this.parentNode.dom, "content" );
	dom.innerHTML = "";
	var text = document.createTextNode( this.getText() );
	dom.appendChild( text );
	if ( this.parentNode.attributes["author"] == JSOT.Rpc.jid )
	{
		var a = document.createElement("a");
		a.href = "#";
		a.className = "editlink";
		a.innerHTML = "Edit";
		var self = this;
		a.onclick = function() { showEditMessage( self ); }
		dom.appendChild(a);
	}
}

function commentTextChange( eventArgs )
{
	this.dom.innerHTML = "";
	var span = document.createElement("span");
	span.className = "commentspan";
	this.dom.appendChild( span );
	var a = document.createElement("a");
	a.className = "username";
	a.href = "#";
	a.appendChild( document.createTextNode( this.attributes["author"] ) );
	span.appendChild( a );
	span.appendChild( document.createTextNode( " - " + this.getText() + " " ) );

	if ( this.attributes["author"] == JSOT.Rpc.jid )
	{
		var a = document.createElement("a");
		a.href = "#";
		a.className = "editlink";
		a.innerHTML = "Edit";
		var self = this;
		a.onclick = function() { showEditComment( self ); }
		span.appendChild(a);
	}

	var span2 = document.createElement("span");
	span2.className = "commentdate";
	span2.appendChild( document.createTextNode( this.attributes["date"] ) );
	span.appendChild( span2 );  
}

/**
 * Called when the message element in the wavelet document has a new child,
 * i.e. someone commented on the message, liked it, ...
 */
function messageNewChild( eventArgs )
{
	var child = eventArgs.element;
	
	if ( child.type == "content" )
	{
		child.getEvent("textChange").addListener( contentTextChange, child );
		child.getEvent("textChange").emit( new JSOT.Doc.EventArgs( eventArgs.doc, "textChange", child ) );
	}
	else if ( child.type == "like" )
	{
		updateLike( this, null );
	}
	else if ( child.type == "comment" )
	{
		var dom = getElementByClass( this.dom, "content" );
		// Doe the hline exist already?
		var hline = getElementByClass( this.dom, "hline" );
		if ( !hline )
		{
			hline = document.createElement("div");
			hline.className = "hline";
			dom.parentNode.insertBefore( hline, dom.nextSibling );
		}
		var comment = document.createElement("div");
		comment.className = "comment";
		child.dom = comment;

		child.getEvent("textChange").addListener( commentTextChange, child );
		child.getEvent("textChange").emit( new JSOT.Doc.EventArgs( eventArgs.doc, "textChange", child ) );
		
		// Where to insert this comment
		var before = child.nextSibling;
		dom.parentNode.insertBefore( comment, before ? before.dom : null );
	}
}

/**
 * Called when the message element in the wavelet document has a new child,
 * i.e. someone commented on the message, liked it, ...
 */
function messageRemoveChild( eventArgs )
{
	var child = eventArgs.element;

	if ( child.type == "content" )
	{
		// Should not happen anyway
	}
	else if ( child.type == "like" )
	{
		updateLike( this, child.attributes["author"] );
	}
	else if ( child.type == "comment" )
	{
		// Delete the comment
		child.dom.parentNode.removeChild( child.dom );
		delete child.dom;
	  
		// How many people still like or comment this?
		var likes = 0;
		var comments = 0;
		for( var i = this.start_index + 1; i < this.end_index; ++i )
		{
			if ( typeof(this.doc.content[i]) != "string" )
			{
				if ( this.doc.content[i].type == "like" )
					likes++;
				else if ( this.doc.content[i].type == "comment" )
					comments++;
			}
		}
	  
		if ( likes == 0 && comments == 0 )
		{
			var hline = getElementByClass( this.dom, "hline" );
			if ( hline )
				hline.parentNode.removeChild( hline );
		}
	}
}

/**
 * Called when the wavelet document containing the message tag has a new child.
 */
function messageDocNewChild( eventArgs )
{
	var child = eventArgs.element;

	if ( child.type == "message" )
	{
		child.getEvent("newChild").addListener( messageNewChild, child );
		child.getEvent("removeChild").addListener( messageRemoveChild, child );
		
		var mdom = newMessage(this);
		child.dom = mdom;
		
		var userName = getElementByClass( mdom, "username" );
		var text = document.createTextNode( child.attributes[ "author" ] );
		userName.appendChild( text );

		var date = getElementByClass( mdom, "messagedate" );
		var text = document.createTextNode( child.attributes[ "date" ] );
		date.appendChild( text );
		
		eventArgs.doc.dom = mdom;
		// return mdom;
	}
	// return null;
};

/**
 * Called when the wavelet document containing the list of messages has a new child.
 */
function conversationNewChild( eventArgs )
{
	var child = eventArgs.element;
  
	var wave = JSOT.Wave.getWave( "w+wall", "wave1.vs.uni-due.de" );
	var wavelet = wave.getWavelet( "conv+root", "wave1.vs.uni-due.de" );

	if ( child.type == "message" )
	{
		var d = wavelet.getDoc( child.attributes[ "id" ] );
		if ( !d )
			return;
		d.getEvent("newChild").addListener( messageDocNewChild, d );
		d.createGUI();
		var dom = document.getElementById( "messages" );
		var next = child.nextSibling;
		dom.insertBefore( d.dom, next ? next.dom : null );
		child.dom = d.dom;
	}
};

/**
 * Called when the wavelet document containing the list of messages removes a child.
 */
function conversationRemoveChild( eventArgs )
{
	var child = eventArgs.element;
  
	var wave = JSOT.Wave.getWave( "w+wall", "wave1.vs.uni-due.de" );
	var wavelet = wave.getWavelet( "conv+root", "wave1.vs.uni-due.de" );

	if ( child.type == "message" )
	{
		var d = wavelet.getDoc( child.attributes[ "id" ] );
		if ( !d )
			return null;
		child.dom.parentNode.removeChild( child.dom );
	}
};

/**
 * Called when the user clicks on the publish button.
 * It submits a delta to the wave server.
 */
function publish()
{
	var wave = JSOT.Wave.getWave( "w+wall", "wave1.vs.uni-due.de" );
	var wavelet = wave.getWavelet( "conv+root", "wave1.vs.uni-due.de" );
	var conversationDoc = wavelet.getDoc("conversation");
	var blipid = "b+" + Math.random();
	
	var mutations = [];

	var m2 = new protocol.ProtocolWaveletOperation_MutateDocument();
	m2.document_id = blipid;
	m2.document_operation = new protocol.ProtocolDocumentOperation();
	var docop = m2.document_operation;
	docop.component.push( protocol.ProtocolDocumentOperation.newElementStart( "message", [ protocol.ProtocolDocumentOperation.newKeyValuePair( "author", JSOT.Rpc.jid ) , protocol.ProtocolDocumentOperation.newKeyValuePair( "date", "10. March" ) ] ) );
	docop.component.push( protocol.ProtocolDocumentOperation.newElementStart( "content" ) );
	docop.component.push( protocol.ProtocolDocumentOperation.newCharacters( document.getElementById("inputtext").value ) );
	docop.component.push( protocol.ProtocolDocumentOperation.newElementEnd() );
	docop.component.push( protocol.ProtocolDocumentOperation.newElementEnd() );
	mutations.push(m2);

	var m1 = new protocol.ProtocolWaveletOperation_MutateDocument();
	m1.document_id = "conversation";
	m1.document_operation = new protocol.ProtocolDocumentOperation();
	var docop = m1.document_operation;
	docop.component.push( protocol.ProtocolDocumentOperation.newElementStart( "message", [ protocol.ProtocolDocumentOperation.newKeyValuePair( "id", blipid ) ] ) );
	docop.component.push( protocol.ProtocolDocumentOperation.newElementEnd() );
	if ( conversationDoc.itemCount() > 0 )
		docop.component.push( protocol.ProtocolDocumentOperation.newRetainItemCount( conversationDoc.itemCount() ) );
	mutations.push(m1);
  
	wavelet.submitMutations( mutations );

	document.getElementById("inputtext").value = "";
}

/**
 * Called when the user clicks on the 'like' button.
 * It submits a delta to the wave server.
 *
 * @param m is the name of the wavelet document which contains the message.
 */
function like(m)
{
	var wave = JSOT.Wave.getWave( "w+wall", "wave1.vs.uni-due.de" );
	var wavelet = wave.getWavelet( "conv+root", "wave1.vs.uni-due.de" );
	var doc = wavelet.getDoc(m);

	var mutations = [];
	var m2 = new protocol.ProtocolWaveletOperation_MutateDocument();
	m2.document_id = m;
	m2.document_operation = new protocol.ProtocolDocumentOperation();
	var docop = m2.document_operation;

	var retain = 0;
	// Do I like it already? In this case dislike it
	for( var i = 0; i < doc.content.length; ++i )
	{
		if ( typeof(doc.content[i]) != "string" )
		{
			if ( doc.content[i].type == "like" && doc.content[i].attributes["author"] == JSOT.Rpc.jid )
			{
				docop.component.push( protocol.ProtocolDocumentOperation.newRetainItemCount( retain ) );
				docop.component.push( protocol.ProtocolDocumentOperation.newDeleteElementStart( "like", 
																							[ protocol.ProtocolDocumentOperation.newKeyValuePair( "author", JSOT.Rpc.jid ),
																							  protocol.ProtocolDocumentOperation.newKeyValuePair( "date", doc.content[i].attributes["date"] ) ] ) );
				docop.component.push( protocol.ProtocolDocumentOperation.newDeleteElementEnd() );
				docop.component.push( protocol.ProtocolDocumentOperation.newRetainItemCount( doc.itemCount() - retain - 2 ) );
				mutations.push(m2);

				// Apply locally and send to the server
				wavelet.submitMutations( mutations );
				return;
			}
			else
				retain++;
		}
		else
			retain += doc.content[i].length;
		  
	}

	// Like it.
	docop.component.push( protocol.ProtocolDocumentOperation.newRetainItemCount( doc.itemCount() - 1 ) );
	docop.component.push( protocol.ProtocolDocumentOperation.newElementStart( "like", [ protocol.ProtocolDocumentOperation.newKeyValuePair( "author", JSOT.Rpc.jid ) , protocol.ProtocolDocumentOperation.newKeyValuePair( "date", "10. March" ) ] ) );
	docop.component.push( protocol.ProtocolDocumentOperation.newElementEnd() );
	docop.component.push( protocol.ProtocolDocumentOperation.newRetainItemCount( 1 ) );
	mutations.push(m2);

	// Apply locally and send to the server
	wavelet.submitMutations( mutations );
}

/**
 * Called when the user clicks on the publish button for a comment.
 * It submits a delta to the wave server.
 *
 * @param m is the name of the wavelet document which contains the message.
 */
function publishComment(m)
{
	var wave = JSOT.Wave.getWave( "w+wall", "wave1.vs.uni-due.de" );
	var wavelet = wave.getWavelet( "conv+root", "wave1.vs.uni-due.de" );
	var doc = wavelet.getDoc(m);
	var dom = doc.content[0].dom;
	var textarea = getElementByClass( dom, "commenttextarea" );
	var mutations = [];

	var m2 = new protocol.ProtocolWaveletOperation_MutateDocument();
	m2.document_id = m;
	m2.document_operation = new protocol.ProtocolDocumentOperation();
	var docop = m2.document_operation;
	docop.component.push( protocol.ProtocolDocumentOperation.newRetainItemCount( doc.itemCount() - 1 ) );
	docop.component.push( protocol.ProtocolDocumentOperation.newElementStart( "comment", [ protocol.ProtocolDocumentOperation.newKeyValuePair( "author", JSOT.Rpc.jid ) , protocol.ProtocolDocumentOperation.newKeyValuePair( "date", "10. March" ) ] ) );
	docop.component.push( protocol.ProtocolDocumentOperation.newElementStart( "content" ) );
	docop.component.push( protocol.ProtocolDocumentOperation.newCharacters( textarea.value ) );
	docop.component.push( protocol.ProtocolDocumentOperation.newElementEnd() );
	docop.component.push( protocol.ProtocolDocumentOperation.newElementEnd() );
	docop.component.push( protocol.ProtocolDocumentOperation.newRetainItemCount( 1 ) );
	mutations.push(m2);

	// Apply locally and send to the server
	wavelet.submitMutations( mutations );

	deleteCommentBox(m);
}

/**
 * GUI
 */
function createCommentBox(m)
{
	var wave = JSOT.Wave.getWave( "w+wall", "wave1.vs.uni-due.de" );
	var wavelet = wave.getWavelet( "conv+root", "wave1.vs.uni-due.de" );
	var doc = wavelet.getDoc(m);
	var dom = doc.content[0].dom;
	if ( getElementByClass( dom, "commentbox" ) )
		return;
		
	var before = getElementByClass( dom, "messagecontrolsbox" );
	var div = document.createElement("div");
	div.className = "commentbox";
	var html = '<span class="commentimage"><img src="https://mail.google.com/mail/images/blue_ghost.jpg" class="userimage" /></span>' +
			   '<div style="display:inline;">' +
					'<div class="commentnamebox"><a href="#" class="commentauthor">Torben Weis</a></div>' +
					'<div class="commenttextbox">' +
						'<textarea class="commenttextarea"></textarea>' +
					'</div>' +
				'</div>' +
					'<div class="commentbuttonbox">' +
						'<input type="button" value="Publish" class="controlpubcomment" /> <input type="button" class="controldelcomment" value="Cancel" />' +
					'</div>' +
					'<div style="clear:both"></div>' +
				'</div>';
	div.innerHTML = html;
	
	// Connect button with event handler
	var delcomment = getElementByClass( div, "controldelcomment" );
	delcomment.onclick = function() { deleteCommentBox( doc.docId ) };

	// Connect button with event handler
	var pubcomment = getElementByClass( div, "controlpubcomment" );
	pubcomment.onclick = function() { publishComment( doc.docId ) };

	before.parentNode.insertBefore( div, before.nextSibling );
}

/**
 * GUI
 */
function deleteCommentBox(m)
{
	var wave = JSOT.Wave.getWave( "w+wall", "wave1.vs.uni-due.de" );
	var wavelet = wave.getWavelet( "conv+root", "wave1.vs.uni-due.de" );
	var doc = wavelet.getDoc(m);
	var dom = doc.content[0].dom;
	var comment = getElementByClass( dom, "commentbox" );
	if ( comment )
	{
		comment.parentNode.removeChild( comment );
	}
}

function showEditMessage( content )
{
	var message = content.parentNode;
	var dom = getElementByClass( message.dom, "content" );
	dom.innerHTML = '<div><textarea class="changetextarea"></textarea></div>' +
					'<div><input type="button" value="Publish" class="editpublish" /> <input type="button" value="Delete" class="editdelete" /> <input type="button" value="Cancel" class="editcancel"/></div>';
				
	var text = document.createTextNode( content.getText() );
	var ta = getElementByClass( dom, "changetextarea" );
	ta.appendChild( text );
	
	var b = getElementByClass( dom, "editcancel" );
	b.onclick = function() { hideEditMessage( content ); }
	
	var b = getElementByClass( dom, "editpublish" );
	b.onclick = function() { updateContent( message ); }	
	
	var b = getElementByClass( dom, "editdelete" );
	b.onclick = function() { deleteMessage( message ); }
}

function updateContent( message )
{
	var newText = getElementByClass( message.dom, "changetextarea" ).value;
	// Remove the HTML for editing the message
	// var dom = getElementByClass( message.dom, "content" );
	// dom.innerHTML = "";
	
	var wave = JSOT.Wave.getWave( "w+wall", "wave1.vs.uni-due.de" );
	var wavelet = wave.getWavelet( "conv+root", "wave1.vs.uni-due.de" );
	var doc = message.doc;
	var content = message.getElementByType("content");
	var pos = content.itemCountBefore();
	var oldText = content.getText();

	var mutations = [];

	var m2 = new protocol.ProtocolWaveletOperation_MutateDocument();
	m2.document_id = doc.docId;
	m2.document_operation = new protocol.ProtocolDocumentOperation();
	var docop = m2.document_operation;
	docop.component.push( protocol.ProtocolDocumentOperation.newRetainItemCount( pos + 1 ) );
	docop.component.push( protocol.ProtocolDocumentOperation.newDeleteCharacters( oldText ) );
	docop.component.push( protocol.ProtocolDocumentOperation.newCharacters( newText ) );
	docop.component.push( protocol.ProtocolDocumentOperation.newRetainItemCount( doc.itemCount() - pos - 1 - oldText.length ) );
	mutations.push(m2);

	// Apply locally and send to the server
	wavelet.submitMutations( mutations );
}

function deleteMessage( message )
{
	var wave = JSOT.Wave.getWave( "w+wall", "wave1.vs.uni-due.de" );
	var wavelet = wave.getWavelet( "conv+root", "wave1.vs.uni-due.de" );

	var doc = wavelet.getDoc("conversation");
	// Find the <message id="xxx"> element where xxx == docId of the message
	var m = doc.getElementById( message.doc.docId );
	var pos = m.itemCountBefore();
	
	var mutations = [];

	var m2 = new protocol.ProtocolWaveletOperation_MutateDocument();
	m2.document_id = doc.docId;
	m2.document_operation = new protocol.ProtocolDocumentOperation();
	var docop = m2.document_operation;
	docop.component.push( protocol.ProtocolDocumentOperation.newRetainItemCount( pos ) );
	docop.component.push( protocol.ProtocolDocumentOperation.newDeleteElementStart( "message", [ protocol.ProtocolDocumentOperation.newKeyValuePair( "id", message.doc.docId ) ] ) );
	docop.component.push( protocol.ProtocolDocumentOperation.newDeleteElementEnd() );	
	docop.component.push( protocol.ProtocolDocumentOperation.newRetainItemCount( doc.itemCount() - pos - 2 ) );
	mutations.push(m2);

	// Apply locally and send to the server
	wavelet.submitMutations( mutations );
}

function hideEditMessage( content )
{
	var message = content.parentNode;
	var dom = content.dom
	// dom.innerHTML = "";
	message.getEvent("newChild").emit( new JSOT.Doc.EventArgs( content.doc, "newChild", content ) );
}

function showEditComment( comment )
{
	var dom = comment.dom;
	dom.innerHTML = '<div style="margin-left:-15px"><a href="#" class="username"></a></div>' +
					'<div style="margin-left:-15px"><textarea class="changetextarea"></textarea></div>' +
					'<div style="margin-left:-15px"><input type="button" value="Publish" class="editpublish" /> <input type="button" value="Delete" class="editdelete" /> <input type="button" value="Cancel" class="editcancel"/></div>';
				
	var text = document.createTextNode( comment.getText() );
	var ta = getElementByClass( dom, "changetextarea" );
	ta.appendChild( text );

	var b = getElementByClass( dom, "username" );
	var text = document.createTextNode( comment.attributes["author"] );
	b.appendChild(text);

	var b = getElementByClass( dom, "editcancel" );
	b.onclick = function() { hideEditComment( comment ); }
	
	var b = getElementByClass( dom, "editpublish" );
	b.onclick = function() { updateComment( comment ); }	
	
	var b = getElementByClass( dom, "editdelete" );
	b.onclick = function() { deleteComment( comment ); }
	
}

function updateComment( comment )
{
	var newText = getElementByClass( comment.dom, "changetextarea" ).value;
	
	var wave = JSOT.Wave.getWave( "w+wall", "wave1.vs.uni-due.de" );
	var wavelet = wave.getWavelet( "conv+root", "wave1.vs.uni-due.de" );
	var doc = comment.doc;
	var content = comment.getElementByType("content");
	var pos = content.itemCountBefore();
	var oldText = content.getText();

	var mutations = [];

	var m2 = new protocol.ProtocolWaveletOperation_MutateDocument();
	m2.document_id = doc.docId;
	m2.document_operation = new protocol.ProtocolDocumentOperation();
	var docop = m2.document_operation;
	docop.component.push( protocol.ProtocolDocumentOperation.newRetainItemCount( pos + 1 ) );
	docop.component.push( protocol.ProtocolDocumentOperation.newDeleteCharacters( oldText ) );
	docop.component.push( protocol.ProtocolDocumentOperation.newCharacters( newText ) );
	docop.component.push( protocol.ProtocolDocumentOperation.newRetainItemCount( doc.itemCount() - pos - 1 - oldText.length ) );
	mutations.push(m2);

	// Apply locally and send to the server
	wavelet.submitMutations( mutations );
}

function deleteComment( comment )
{
	var wave = JSOT.Wave.getWave( "w+wall", "wave1.vs.uni-due.de" );
	var wavelet = wave.getWavelet( "conv+root", "wave1.vs.uni-due.de" );

	var doc = comment.doc;
	// Find the <message id="xxx"> element where xxx == docId of the message
	var pos = comment.itemCountBefore();
	var oldText = comment.getText();
	var mutations = [];

	var m2 = new protocol.ProtocolWaveletOperation_MutateDocument();
	m2.document_id = doc.docId;
	m2.document_operation = new protocol.ProtocolDocumentOperation();
	var docop = m2.document_operation;
	docop.component.push( protocol.ProtocolDocumentOperation.newRetainItemCount( pos ) );
	docop.component.push( protocol.ProtocolDocumentOperation.newDeleteElementStart( "comment",
																  [ protocol.ProtocolDocumentOperation.newKeyValuePair( "author", comment.attributes["author"] ),
																	protocol.ProtocolDocumentOperation.newKeyValuePair( "date", comment.attributes["date"] )] ) );
	docop.component.push( protocol.ProtocolDocumentOperation.newDeleteElementStart( "content" ) );
	docop.component.push( protocol.ProtocolDocumentOperation.newDeleteCharacters( oldText ) );
	docop.component.push( protocol.ProtocolDocumentOperation.newDeleteElementEnd() );
	docop.component.push( protocol.ProtocolDocumentOperation.newDeleteElementEnd() );
	docop.component.push( protocol.ProtocolDocumentOperation.newRetainItemCount( doc.itemCount() - pos - 4 - oldText.length ) );
	mutations.push(m2);

	// Apply locally and send to the server
	wavelet.submitMutations( mutations );
}

function hideEditComment( comment )
{
	var dom = comment.dom
	dom.parentNode.removeChild( dom );
	comment.parentNode.getEvent("newChild").emit( new JSOT.Doc.EventArgs( comment.doc, "newChild", comment ) );
}

	</script>
</body>	